package com.bobi.ecofavor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.bobi.ecofavor.common.enums.CouponRangeEnum;
import com.bobi.ecofavor.common.enums.CouponStatusEnum;
import com.bobi.ecofavor.common.utils.JsonResponse;
import com.bobi.ecofavor.mapper.CouponCategoryMapper;
import com.bobi.ecofavor.mapper.StoreMapper;
import com.bobi.ecofavor.model.domain.Coupon;
import com.bobi.ecofavor.mapper.CouponMapper;
import com.bobi.ecofavor.model.domain.CouponCategory;
import com.bobi.ecofavor.model.domain.Store;
import com.bobi.ecofavor.model.dto.CouponDto;
import com.bobi.ecofavor.model.vo.CouponCenterVO;
import com.bobi.ecofavor.service.CouponCategoryService;
import com.bobi.ecofavor.service.CouponService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bobi.ecofavor.service.StoreService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 优惠券 服务实现类
 * </p>
 *
 * @author wenyuan
 * @since 2023-10-21
 */
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements CouponService {

    @Autowired
    private CouponMapper couponMapper;

    @Autowired
    private CouponCategoryService couponCategoryService;

    @Autowired
    private StoreService storeService;

    /**
     * 得到未使用优惠券列表
     * @param userId 用户id
     * @return JsonResponse
     */
    @Transactional
    @Override
    public List<CouponDto> getUnsedCoupons(Integer userId) {
        ArrayList<CouponDto> couponDtos = new ArrayList<>();
        // 1. 获取到未使用的优惠券列表
        QueryWrapper<Coupon> couponQueryWrapper = new QueryWrapper<>();
        // 1.1. 指定用户
        couponQueryWrapper.eq("user_id", userId);
        // 1.2. 指定状态，不能保证一定没过期，但保证一定领到了
        couponQueryWrapper.eq("coupon_status", CouponStatusEnum.USEABLE.getCode());
        // 1.3. 比较截止日期是否过期
        couponQueryWrapper.gt("end_time", DateUtil.date());
        ArrayList<Coupon> couponList = (ArrayList<Coupon>) couponMapper.selectList(couponQueryWrapper);

        // 2. 将已经过期的优惠券状态设为过期
        LambdaUpdateWrapper<Coupon> lambdaUpdateWrapper =  new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Coupon::getUserId, userId).in(Coupon::getCouponStatus, CouponStatusEnum.USEABLE.getCode(), CouponStatusEnum.UNACCEPTED.getCode())
                .lt(Coupon::getEndTime, DateUtil.date())
                .set(Coupon::getCouponStatus, CouponStatusEnum.OVERTIME.getCode());
        couponMapper.update(null, lambdaUpdateWrapper);

        if (couponList == null || couponList.size() == 0) {
            return null;
        }
        // 3. 得到详细信息，复制到Dto中
        getCouponDtoList(couponDtos, couponList);
        // 4. 返回 CouponDtos
        return couponDtos;
    }

    /**
     * 根据优惠券 id 得到优惠券种类信息，将优惠券种类信息和优惠券标识得到转换为 CouponDto
     * 最后添加到 CouponDtoList中
     * @param couponDtos 优惠券Dto最后获得结果
     * @param couponList 优惠券原始列表
     */
    private void getCouponDtoList(ArrayList<CouponDto> couponDtos, ArrayList<Coupon> couponList) {
        for (Coupon coupon : couponList) {
            CouponDto couponDto = new CouponDto();
            BeanUtil.copyProperties(coupon, couponDto);
            CouponCategory couponCategory = couponCategoryService.getById(coupon.getCouponCategoryId());
            BeanUtil.copyProperties(couponCategory, couponDto, "id", "couponStatus", "beginTime", "endTime", "createTime", "updateTime", "isDeleted");
            // 设置优惠券标识
            setCouponMark(couponDto);

            couponDtos.add(couponDto);
        }
    }

    /**
     * 根据couponDto的店铺id字段设置优惠券标识
     * @param couponDto 优惠券转换对象
     */
    private void setCouponMark(CouponDto couponDto) {

        if (couponDto.getUseRange() != CouponRangeEnum.STORE.getCode())
            couponDto.setCouponMark();
        else {
            Store store = storeService.getById(couponDto.getStoreId());
            couponDto.setCouponMark(store.getStoreName());
        }

    }

    /**
     * 得到历史优惠券列表
     * @param userId 用户id
     * @return JsonResponse
     */
    @Override
    public JsonResponse getPastCoupons(Integer userId) {
        ArrayList<CouponDto> couponDtos = new ArrayList<>();
        // 1. 获取到历史的优惠券列表
        LambdaQueryWrapper<Coupon> couponQueryWrapper = new LambdaQueryWrapper<>();
        // 1.1. 指定用户
        couponQueryWrapper.eq(Coupon::getUserId, userId);
        // 1.2. 指定状态
        couponQueryWrapper.in(Coupon::getCouponStatus, CouponStatusEnum.USED.getCode(), CouponStatusEnum.OVERTIME.getCode(), CouponStatusEnum.OFFLIST.getCode());
        ArrayList<Coupon> couponList = (ArrayList<Coupon>) couponMapper.selectList(couponQueryWrapper);

        if (couponList == null || couponList.size() == 0) {
            return JsonResponse.success(null);
        }

        // 2. 得到详细信息，复制到Dto中
        getCouponDtoList(couponDtos, couponList);
        // 3. 返回 CouponDtos
        return JsonResponse.success(couponDtos);
    }

    @Transactional
    @Override
    public JsonResponse getAllUnacceptedCoupons(Integer userId) {
        CouponCenterVO couponCenterVO = new CouponCenterVO();
        // 1. 根据用户id查询所有 状态为 UNACCEPTED
        LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Coupon::getUserId, userId).eq(Coupon::getCouponStatus, CouponStatusEnum.UNACCEPTED.getCode());
        List<Coupon> coupons = couponMapper.selectList(queryWrapper);

        if (coupons == null || coupons.size() == 0)
            return JsonResponse.success(null);

        // 2. 根据couponid 得到详细信息
        ArrayList<CouponDto> pfCouponDtos = new ArrayList<>();
        ArrayList<CouponDto> storeCouponDtos = new ArrayList<>();

        for (Coupon coupon : coupons) {
            // 2.1. 平台发券：优惠券种类不为 STORE的
            CouponDto pfCouponDto = new CouponDto();
            BeanUtil.copyProperties(coupon, pfCouponDto);
            LambdaQueryWrapper<CouponCategory> pfQueryWrapper = new LambdaQueryWrapper<>();
            pfQueryWrapper.eq(CouponCategory::getId, coupon.getCouponCategoryId())
                    .ne(CouponCategory::getUseRange, CouponRangeEnum.STORE.getCode());
            CouponCategory pfCouponCategory = couponCategoryService.getOne(pfQueryWrapper);

            // 2.1.1. 判断是否查到有平台的优惠券再copy
            if (pfCouponCategory != null) {
                BeanUtil.copyProperties(pfCouponCategory, pfCouponDto, "id", "couponStatus", "beginTime", "endTime", "createTime", "updateTime", "isDeleted");
                // 设置优惠券标识
                setCouponMark(pfCouponDto);
                // 添加到平台优惠券列表
                pfCouponDtos.add(pfCouponDto);
            }

            // 2.2. 商家发券：优惠券种类为 STORE的
            CouponDto storeCouponDto = new CouponDto();
            BeanUtil.copyProperties(coupon, storeCouponDto);
            LambdaQueryWrapper<CouponCategory> storeQueryWrapper = new LambdaQueryWrapper<>();
            storeQueryWrapper.eq(CouponCategory::getId, coupon.getCouponCategoryId())
                    .eq(CouponCategory::getUseRange, CouponRangeEnum.STORE.getCode());
            CouponCategory storeCouponCategory = couponCategoryService.getOne(storeQueryWrapper);

            // 2.2.1. 判断是否查到有商铺的优惠券种类再copy
            if (storeCouponCategory != null) {
                BeanUtil.copyProperties(storeCouponCategory, storeCouponDto, "id", "couponStatus", "beginTime", "endTime", "createTime", "updateTime", "isDeleted");

                // 设置优惠券标识
                setCouponMark(storeCouponDto);
                // 添加到平台优惠券列表
                storeCouponDtos.add(storeCouponDto);
            }
        }

        // 3. 添加到 CouponCenterVO
        couponCenterVO.setPlateformCouponList(pfCouponDtos);
        couponCenterVO.setStoreCouponList(storeCouponDtos);
        return JsonResponse.success(couponCenterVO);
    }

    /**
     * 领取优惠券
     * @param id 优惠券id
     * @return JSONResponse
     */
    @Override
    public JsonResponse acceptCoupon(Integer id, Integer categoryId) {
        // 1. 更改优惠券种类的数量 减一
        // 注意：添加优惠券种类时，给指定用户或是所有用户发优惠券的同时，应设置 每一张优惠券的 结束时间 为 优惠券种类结束时间
        CouponCategory couponCategory = couponCategoryService.getById(categoryId);
        LocalDateTime finalEndTime = couponCategory.getFinalEndTime();

        UpdateWrapper<CouponCategory> couponCategoryUpdateWrapper = new UpdateWrapper<>();
        couponCategoryUpdateWrapper.eq("id", categoryId);
        couponCategoryUpdateWrapper.gt("remain_quantity - 1 ", 0);
        couponCategoryUpdateWrapper.setSql("remain_quantity = remain_quantity - 1");
        boolean update = couponCategoryService.update(null, couponCategoryUpdateWrapper);
        if (!update) {
            return JsonResponse.success(null, "优惠券已经被抢空了");
        }


        // 2. 更改优惠券的状态为待使用，同时更新结束日期，和开始日期
        LambdaUpdateWrapper<Coupon> couponUpdateWrapper = new LambdaUpdateWrapper<>();
        couponUpdateWrapper.eq(Coupon::getId, id)
                .set(Coupon::getCouponStatus, CouponStatusEnum.USEABLE.getCode())
                .set(Coupon::getBeginTime, LocalDateTime.now())
                .set(Coupon::getEndTime, finalEndTime);
        couponMapper.update(null, couponUpdateWrapper);

        return JsonResponse.success(null, "更新成功");
    }
}
